#include"LockGuard.hpp"
#include<queue>
#include<pthread.h>
#include<iostream>
#include<unistd.h>

using namespace std;

const int g_DefauleCap=5;

template <class T>
class BlockQueue
{
public: 
    BlockQueue(int capacity=g_DefauleCap)
    {
        pthread_mutex_init(_mutex,nullptr);
        pthread_cond_init(_prod,nullptr);
        pthread_cond_init(_cons,nullptr);
    }
    void push(const T& in)
    {
        LockGuard lockguard(_mutex);
        while(isQueueFull())
        {
            pthread_cond_wait(_cond,_mutex);
        }
        _bq.push(in);
        pthread_cond_signal(_cons);
    }
    void pop(T* out)
    {
        LockGuard lockguard(_mutex);
        while(isQueueFull())
        {
            pthread_cond_wait(_cons,_mutex);
        }
        *out=_bq.front();
        _bq.pop();
        pthread_cond_signal(_prod);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(_mutex);
        pthread_cond_destroy(_prod);
        pthread_cond_destroy(_cons);
    }
private:
    bool isQueueEmpty()
    {
        return _bq.size()==0;
    }
    bool isQueueFull()
    {
        return _bq.size()==_capacity;
    }
private:
    int _capacity;
    queue<T> _bq;
    pthread_mutex_t* _mutex;
    pthread_cond_t* _prod;
    pthread_cond_t* _cons;
};